
#include "stdio.h"
#include "unistd.h"
#include "sys/types.h"
#include "sys/stat.h"
#include "fcntl.h"
#include "stdlib.h"
#include "string.h"
#include <stdio.h>
#include <unistd.h>

#define LCD_W 240
#define LCD_H 320
#define portTICK_RATE_MS 100.0
#define PARALLEL_LINES 1
#define USE_HORIZONTAL 1 //定义液晶屏顺时针旋转方向  0-0度旋转，1-90度旋转，2-180度旋转，3-270度旋转


#define PIN_ID_MOSI           0
#define PIN_ID_MISO           1
#define PIN_ID_CLK            2
#define PIN_ID_CS             3
#define PIN_ID_RESET          4
#define PIN_ID_DC             5

#define PIN_PROCESS  10
#define WRITE_BYTES  11
#define FILL_SCREEN  12

//画笔颜色
#define WHITE 0xFFFF
#define BLACK 0x0000
#define BLUE 0x001F
#define BRED 0XF81F
#define GRED 0XFFE0
#define GBLUE 0X07FF
#define RED 0xF800
#define MAGENTA 0xF81F
#define GREEN 0x07E0
#define CYAN 0x7FFF
#define YELLOW 0xFFE0
#define BROWN 0XBC40 //棕色
#define BRRED 0XFC07 //棕红色
#define GRAY 0X8430  //灰色
//GUI颜色

#define DARKBLUE 0X01CF  //深蓝色
#define LIGHTBLUE 0X7D7C //浅蓝色
#define GRAYBLUE 0X5458  //灰蓝色

unsigned char pin_ctrl_data[8];
int tft_drv;
unsigned char writeData[25603];

#define LCD_MOSI_Clr    tftPinCtrl(PIN_ID_MOSI,0);
#define LCD_MOSI_Set    tftPinCtrl(PIN_ID_MOSI,1);
#define LCD_SCLK_Clr    tftPinCtrl(PIN_ID_CLK,0);
#define LCD_SCLK_Set    tftPinCtrl(PIN_ID_CLK,1);
#define LCD_CS_Clr      tftPinCtrl(PIN_ID_CS,0)
#define LCD_CS_Set      tftPinCtrl(PIN_ID_CS,1)
#define LCD_DC_Clr      tftPinCtrl(PIN_ID_DC,0);
#define LCD_DC_Set      tftPinCtrl(PIN_ID_DC,1);
#define LCD_RESET_Clr   tftPinCtrl(PIN_ID_RESET,0);
#define LCD_RESET_Set   tftPinCtrl(PIN_ID_RESET,1);

void tftPinCtrl(int pinNum,int pinLvl){
    // tft_drv = open("/dev/tft_hx8347g", O_RDWR);
    pin_ctrl_data[0]=PIN_PROCESS;
    pin_ctrl_data[1]=pinNum;
    pin_ctrl_data[2]=pinLvl;
    write(tft_drv,&pin_ctrl_data,3);
    // close(tft_drv);
}

void osDelay(int ms){
    sleep(ms/portTICK_RATE_MS);
}

static unsigned short * frameData; 
static int fps = 0;

typedef struct
{
    unsigned short width;   //LCD 宽度
    unsigned short height;  //LCD 高度
    unsigned short id;      //LCD ID
    unsigned char dir;      //横屏还是竖屏控制：0，竖屏；1，横屏。
    unsigned short wramcmd; //开始写gram指令
    unsigned short setxcmd; //设置x坐标指令
    unsigned short setycmd; //设置y坐标指令
} _lcd_dev;
static _lcd_dev lcddev;

typedef struct
{
    unsigned char cmd;
    unsigned char data[16];
    unsigned char databytes; //No of data in data; bit 7 = delay after set; 0xFF = end of cmds.
} lcd_init_cmd_t;

#define CMD_DELAY 0xFE

static const lcd_init_cmd_t lcd_init_cmds[] = {
    //*************1.54 inch ST7789V 初始化**********//
    {0xEA, {0x00}, 1}, // Command page 0
    {0xEB, {0x00}, 1}, // SUB_SEL=0xF6
    // Power saving for HX8357-A
    {0xEC, {0x3C}, 1}, // Command page 0
    {0xED, {0xC4}, 1}, // GENON=0x00
    {0xE8, {0x48}, 1}, // EQVCI_M1=0x00
    {0xE9, {0x38}, 1}, // EQGND_M1=0x1C
    {0xF1, {0x01}, 1}, // EQVCI_M0=0x1C
    {0xF2, {0x00}, 1}, // EQGND_M0=0x1C
    {0x27, {0xA3}, 1}, // For GRAM read/write speed
    {0x2E, {0x76}, 1}, //For Gate timing, prevent the display abnormal in RGB I/F
    {0x60, {0x08}, 1},
    {0x29, {0x01}, 1},
    {0x2B, {0x02}, 1},
    {0x36, {0x09}, 1},
    // Gamma
    {0x40, {0x00}, 1},
    {0x41, {0x01}, 1},
    {0x42, {0x01}, 1},
    {0x43, {0x12}, 1},
    {0x44, {0x10}, 1},
    {0x45, {0x24}, 1},
    {0x46, {0x05}, 1},
    {0x47, {0x5B}, 1},
    {0x48, {0x03}, 1},
    {0x49, {0x11}, 1},
    {0x4A, {0x17}, 1},
    {0x4B, {0x18}, 1},
    {0x4C, {0x19}, 1},
    {0x50, {0x1B}, 1},
    {0x51, {0x2F}, 1},
    {0x52, {0x2D}, 1},
    {0x53, {0x3E}, 1},
    {0x54, {0x3E}, 1},
    {0x55, {0x3F}, 1},
    {0x56, {0x30}, 1},
    {0x57, {0x6E}, 1},
    {0x58, {0x06}, 1},
    {0x59, {0x07}, 1},
    {0x5A, {0x08}, 1},
    {0x5B, {0x0E}, 1},
    {0x5C, {0x1C}, 1},
    {0x5D, {0xCC}, 1},
    // Set GRAM area 320x240
    {0x02, {0x00}, 1},
    {0x03, {0x00}, 1},
    {0x04, {0x00}, 1},
    {0x05, {0xEF}, 1},
    {0x06, {0x00}, 1},
    {0x07, {0x00}, 1},
    {0x08, {0x01}, 1},
    {0x09, {0x3F}, 1},
    // Power Setting
    {0xE2, {0x03}, 1},
    {0x1B, {0x1D}, 1},
    {0x1A, {0x01}, 1},
    {0x24, {0x37}, 1}, // Set VCOMH voltage, VHH=0x64
    {0x25, {0x4F}, 1}, // Set VCOML voltage, VML=0x71
    {0x23, {0x6A}, 1}, // Set VCOM offset, VMF=0x52   ////////////60
    // Pow{er on Setting
    {0x18, {0x3A}, 1}, // OSC_EN=1, Start to Oscillate
    {0x19, {0x01}, 1}, // AP=011
    {0x01, {0x00}, 1}, // Normal display(Exit Deep standby mode)
    {0x1F, {0x88}, 1}, // Exit standby mode and Step-up circuit 1 enable
    // GAS_EN=1, VCOMG=0, PON=0, DK=0, XDK=0, DDVDH_TRI=0, STB=0
    {CMD_DELAY, {0}, 5}, //osDelay(5);
    {0x1F, {0x80}, 1},   // Step-up circuit 2 enable
    // GAS_EN=1, VCOMG=0, PON=1, DK=0, XDK=0, DDVDH_TRI=0, STB=0
    {CMD_DELAY, {0}, 5}, //osDelay(5);
    {0x1F, {0x90}, 1},
    {CMD_DELAY, {0}, 5}, //osDelay(5);
    {0x1F, {0xD0}, 1},
    // GAS_EN=1, VCOMG=1, PON=1, DK=0, XDK=1, DDVDH_TRI=0, STB=0
    {CMD_DELAY, {0}, 5}, //osDelay(5);
    // Display ON Setting
    {0x17, {0x05}, 1},    // GON=1, DTE=1, D[1:0]=10
    {CMD_DELAY, {0}, 40}, //osDelay(40)
    {0x28, {0x38}, 1},    // GON=1, DTE=1, D[1:0]=11
    {0x28, {0x3C}, 1},    // 16-bit/pixel

    {0, {0}, 0xff}, //end init

};

void lcd_write_bus(unsigned char dat)
{	
	unsigned char i;
	// LCD_CS_Clr;
	// for(i=0;i<8;i++){			  
	// 	LCD_SCLK_Clr;
	// 	if(dat&0x80){
	// 	   LCD_MOSI_Set;
	// 	}
	// 	else{
	// 	   LCD_MOSI_Clr;
	// 	}
	// 	LCD_SCLK_Set;
	// 	dat<<=1;
	// }	
    pin_ctrl_data[0] = WRITE_BYTES;
    pin_ctrl_data[1] = 0;
    pin_ctrl_data[2] = 0x1;
    pin_ctrl_data[3] = dat;
    write(tft_drv,&pin_ctrl_data,4);
    // LCD_CS_Set;	
}

void lcd_cmd(const unsigned char cmd)
{
    LCD_DC_Clr;//写命令
    lcd_write_bus(cmd);
}


void lcd_data( const unsigned char *data, int len)
{    
    int i;
    LCD_DC_Set;//写数据
    // for (i=0;i<len;i++){
    //     lcd_write_bus(data[i]);
    // }
    
    writeData[0] = WRITE_BYTES;
    writeData[1] = (len)>>8;
    writeData[2] = (len)&0x000000FF;
    memcpy(writeData+3,data,len);
    // printf("length =%d,bin= 0x%x%x\r\n",len,pin_ctrl_data[1],pin_ctrl_data[2]);
    write(tft_drv,&writeData,len+3);

}

void LCD_WriteReg( unsigned char LCD_Reg, unsigned short LCD_RegValue)
{
    unsigned char dataByte[2];
    dataByte[0] = LCD_RegValue >> 8;
    dataByte[1] = LCD_RegValue & 0x00FF;
    
    lcd_cmd(LCD_Reg);    
    lcd_data(&dataByte, 2);
}

void LCD_direction(unsigned char direction)
{
    lcddev.setxcmd = 0x02;
    lcddev.setycmd = 0x06;
    lcddev.wramcmd = 0x22;
    switch (direction)
    {
    case 0:
        lcddev.width = LCD_W;
        lcddev.height = LCD_H;
        //      LCD_WriteReg(0x36,(0<<3)|(0<<6)|(0<<7));//BGR==0,MY==0,MX==0,MV==0
        break;
    case 1:
        lcddev.width = LCD_H;
        lcddev.height = LCD_W;
        LCD_WriteReg(0x16, 0x60);
        //      LCD_WriteReg(0x36,(0<<3)|(0<<7)|(1<<6)|(1<<5));//BGR==0,MY==1,MX==0,MV==1
        break;
    case 2:
        lcddev.width = LCD_W;
        lcddev.height = LCD_H;
        //      LCD_WriteReg(0x36,(0<<3)|(1<<6)|(1<<7));//BGR==0,MY==0,MX==0,MV==0
        break;
    case 3:
        lcddev.width = LCD_H;
        lcddev.height = LCD_W;
        LCD_WriteReg(0x16, 0x20);
        //      LCD_WriteReg(0x36,(0<<3)|(1<<7)|(1<<5));//BGR==0,MY==1,MX==0,MV==1
        break;
    default:
        break;
    }
}

void lcd_init()
{
    printf("lcd init start66\r\n");
    int cmd = 0;

    

    //Initialize non-SPI GPIOs
    // IoTGpioInit(mSpi.pin_dc);
    // IoTGpioSetDir(mSpi.pin_dc, IOT_GPIO_DIR_OUT);
    // IoTGpioInit(mSpi.pin_reset);
    // IoTGpioSetDir(mSpi.pin_reset, IOT_GPIO_DIR_OUT);

    //Reset the display
    LCD_RESET_Clr;
    osDelay(100 / portTICK_RATE_MS);
    LCD_RESET_Set;
    osDelay(100 / portTICK_RATE_MS);

    //Send all the commands
    while (lcd_init_cmds[cmd].databytes != 0xff)
    {
        if (lcd_init_cmds[cmd].cmd == CMD_DELAY)
        {
            osDelay(lcd_init_cmds[cmd].databytes / portTICK_RATE_MS);
        }
        else
        {
            lcd_cmd(lcd_init_cmds[cmd].cmd);
            lcd_data(lcd_init_cmds[cmd].data, lcd_init_cmds[cmd].databytes & 0x1F);
        }
        cmd++;
    }
    LCD_direction(USE_HORIZONTAL); //设置LCD显示方向
    // LCD_LED_SET;                        //点亮背光
    printf("lcd init end\r\n");
    
}

void LCD_SetWindows(unsigned short xStar, unsigned short yStar, unsigned short xEnd, unsigned short yEnd)
{
    LCD_WriteReg(lcddev.setxcmd, xStar >> 8);
    LCD_WriteReg(lcddev.setxcmd + 1, 0x00FF & xStar);
    LCD_WriteReg(lcddev.setxcmd + 2, xEnd >> 8);
    LCD_WriteReg(lcddev.setxcmd + 3, 0x00FF & xEnd);

    LCD_WriteReg(lcddev.setycmd, yStar >> 8);
    LCD_WriteReg(lcddev.setycmd + 1, 0x00FF & yStar);
    LCD_WriteReg(lcddev.setycmd + 2, yEnd >> 8);
    LCD_WriteReg(lcddev.setycmd + 3, 0x00FF & yEnd);

    lcd_cmd(lcddev.wramcmd);
}

void LCD_Clear( unsigned short Color)
{
    //Serial.printf("setxcmd:%d,setycmd:%d,wramcmd:%d",lcddev.setxcmd,lcddev.setycmd,lcddev.wramcmd);
    unsigned int i, m;
    LCD_SetWindows(0, 0, lcddev.width - 1, lcddev.height - 1);
    int oneTimePixels = lcddev.width * PARALLEL_LINES; //
    int lineTimes = lcddev.height / PARALLEL_LINES;
    unsigned char lineData[oneTimePixels * 2];
    for (i = 0; i < lineTimes; i++)
    {
        for (m = 0; m < oneTimePixels; m++)
        {
            lineData[m * 2] = Color >> 8;
            lineData[m * 2 + 1] = Color;
        }
        lcd_data(&lineData, oneTimePixels * 2);
    }
    fps++;
}

void LCD_Clear_TEST(unsigned short Color){
    LCD_SetWindows(0, 0, lcddev.width - 1, lcddev.height - 1);
    LCD_DC_Set;//写数据
    pin_ctrl_data[0] = FILL_SCREEN;
    pin_ctrl_data[1] = Color>>8;
    pin_ctrl_data[2] = Color;
    // pin_ctrl_data[3] = dat;
    write(tft_drv,&pin_ctrl_data,3);
}

void LCD_Fill(unsigned short x1,unsigned short y1,
        unsigned short x2,unsigned short y2,unsigned short *pixelArray){
    unsigned int i, m;
    LCD_SetWindows(x1,y1,x2,y2);
    int oneTimePixels = (x2-x1+1) ; //
    int lineTimes = (y2-y1+1);
    unsigned char lineData[oneTimePixels * 2];
    for (i = 0; i < lineTimes; i++)
    {
        for (m = 0; m < oneTimePixels; m++)
        {
            unsigned short pixel = pixelArray[i*oneTimePixels+m];
            lineData[m * 2] = pixel >> 8;
            lineData[m * 2 + 1] = pixel;
        }
        lcd_data(&lineData, oneTimePixels * 2);
    }
}

void lcd_refresh(){
    // printf("tft_hx8347/lcd_refresh=%d \n",fps++);
    int line=0,i;
    for(i=0;i<lcddev.height-1;i++){
        LCD_Fill(0,i,lcddev.width,i+1,frameData+lcddev.width*i);
    }
}

int main(int argc, char *argv[])
{
    //writeData=(unsigned char *)malloc(700);
    int i;
    tft_drv = open("/dev/tft_hx8347g", O_RDWR);
    LCD_CS_Clr;
    lcd_init();
    unsigned short colorArr[8] = {MAGENTA,BLUE,BRED,GRED,GBLUE,RED,GREEN,YELLOW};
    while(1){
        for ( i = 0; i < 8; i++)
        {
            LCD_Clear(colorArr[i]);
            sleep(1);
        }
    }
    close(tft_drv);
    LCD_CS_Set;
    printf("lcd_clear done\n\r");
	return 0;
}
